﻿using KZ.Express.ENT;
using KZ.Express.Resource;
using KZ.Express.Task;
using KZ.Utilities;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

namespace KZ.Express.Presenter
{
    public interface IOrderListView : IViewBase
    {
        DataTable SupplierCarrier { set; }
    }

    public class OrderListPresenter : PresenterBase
    {
        private new IOrderListView _view;
        private new OrderTask _task;

        public OrderListPresenter(IOrderListView view)
            : base(view, new OrderENT())
        {
            _view = view;
            _task = new OrderTask();
        }

        public DataTable LoadOrder()
        {
            try
            {
                _view.SetMessage(String.Empty, true);
                return _task.LoadDataTable(_view.Search);
            }
            catch (DataAccessException ex)
            {
                throw new BusinessLogicException(ex.Message);
            }
        }

        public void LoadSupplierCarrier()
        {
            try
            {
                _view.SetMessage(String.Empty, true);
                _view.SupplierCarrier = _task.LoadSupplierCarrier();
            }
            catch (DataAccessException ex)
            {
                throw new BusinessLogicException(ex.Message);
            }
        }

        public Dictionary<string, Dictionary<int, string>> ImportExcel(string fileName, out int success, out int unsuccess)
        {
            success = 0;
            unsuccess = 0;
            Excel.Application xlApp = null;
            Excel.Workbooks xlWorkBooks = null;
            Excel.Workbook xlWorkBook = null;
            Excel.Sheets xlWorkSheets = null;
            Excel.Worksheet xlWorkSheet = null;
            Excel.Range range = null;
            Dictionary<string, Dictionary<int, string>> errors = new Dictionary<string, Dictionary<int, string>>();
            try
            {
                xlApp = new Excel.Application();
                xlWorkBooks = xlApp.Workbooks;
                xlWorkBook = xlWorkBooks.Open(fileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, true,
                    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

                SearchCriteria search = new SearchCriteria();
                search.Add("IsCustomer", 1);
                DataTable customers = _task.LoadDataTable<CustomerENT>(search);
                search.Clear();

                DataTable countries = _task.LoadDataTable<CountryENT>(search);

                xlWorkSheets = xlWorkBook.Worksheets;
                int sheetCount = xlWorkSheets.Count;

                int totalCount = 0;
                List<int> endList = new List<int>();
                for (int i = 1; i <= sheetCount; i++)
                {
                    xlWorkSheet = (Excel.Worksheet)xlWorkSheets.get_Item(i);
                    //// get a range to work with
                    range = xlWorkSheet.get_Range("A2", Type.Missing);
                    //// get the end of values toward the bottom, looking in the last column (will stop at first empty cell)
                    range = range.get_End(Microsoft.Office.Interop.Excel.XlDirection.xlDown);
                    //// get the address of the bottom cell
                    string downAddress = range.get_Address(false, false, Microsoft.Office.Interop.Excel.XlReferenceStyle.xlA1, Type.Missing, Type.Missing);
                    int end = Utility.IntParse(downAddress.Remove(0, 1));
                    if (end < 10000)
                        totalCount += end - 1;
                    else
                        end = 10000;
                    endList.Add(end);
                }

                _view.UpdateValueProgressBar(0);
                _view.ChangeProgressBarVisible(true);
                _view.ChangeProgressBarMaximum(totalCount);

                for (int i = 1; i <= sheetCount; i++)
                {
                    xlWorkSheet = (Excel.Worksheet)xlWorkSheets.get_Item(i);
                    range = xlWorkSheet.get_Range("A2", "L" + endList[i - 1]);

                    int rowCount = range.Rows.Count;
                    if (rowCount > 0)
                    {
                        string[] temp = xlWorkSheet.Name.Split('_');
                        if (temp.Length == 2)
                        {
                            search.Clear();
                            search.Add("PartnerCode", temp[0].Trim());
                            SupplierENT supplier = _task.LoadEntity<SupplierENT>(search) as SupplierENT;

                            search.Clear();
                            search.Add("CarrierName", temp[1].Trim());
                            CarrierENT carrier = _task.LoadEntity<CarrierENT>(search) as CarrierENT;

                            if (supplier.PartnerID > 0 && carrier.CarrierID > 0)
                            {
                                for (int j = 1; j <= rowCount; j++)
                                {
                                    if (j + 1 == 276)
                                    {
                                        Console.WriteLine(j.ToString());
                                    }
                                    try
                                    {
                                        ReadLine(range, j, supplier.PartnerID, carrier.CarrierID, customers, countries);
                                        success++;
                                    }
                                    catch (BusinessLogicException ex)
                                    {
                                        unsuccess++;
                                        if (errors.ContainsKey(xlWorkSheet.Name))
                                            errors[xlWorkSheet.Name].Add(j, ex.Message);
                                        else
                                        {
                                            errors.Add(xlWorkSheet.Name, new Dictionary<int, string>());
                                            errors[xlWorkSheet.Name].Add(j, ex.Message);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        if (ex.Message == "Break")
                                            break;
                                        unsuccess++;
                                        if (errors.ContainsKey(xlWorkSheet.Name))
                                            errors[xlWorkSheet.Name].Add(j + 1, ex.Message);
                                        else
                                        {
                                            errors.Add(xlWorkSheet.Name, new Dictionary<int, string>());
                                            errors[xlWorkSheet.Name].Add(j + 1, ex.Message);
                                        }
                                    }

                                    _view.PerformStepProgressBar(1);
                                }
                            }
                        }
                    }
                }

                _view.UpdateValueProgressBar(totalCount);
            }
            catch (Exception ex)
            {
                Log.LogEx(Message.BLM_ERR_GENERAL.ToString(), Log.LogType.Error, ex);
            }
            finally
            {
                xlWorkBook.Close(false, Type.Missing, Type.Missing);
                xlApp.Quit();

                System.Threading.Thread.Sleep(1000);

                Marshal.ReleaseComObject(xlApp);
                if (range != null) Marshal.ReleaseComObject(range);
                if (xlWorkSheet != null) Marshal.ReleaseComObject(xlWorkSheet);
                if (xlWorkSheets != null) Marshal.ReleaseComObject(xlWorkSheets);
                if (xlWorkBook != null) Marshal.ReleaseComObject(xlWorkBook);
                if (xlWorkBooks != null) Marshal.ReleaseComObject(xlWorkBooks);
                if (xlApp != null) Marshal.ReleaseComObject(xlApp);

                _view.ChangeProgressBarVisible(false);
            }

            return errors;
        }

        private void ReadLine(Excel.Range range, int index, int supplierID, int carrierID, DataTable customers, DataTable countries)
        {
            string type = (string)(range.Cells[index, 6] as Excel.Range).Value2;
            string ordernumber;
            try
            {
                ordernumber = ((object)(range.Cells[index, 2] as Excel.Range).Value2).ToString();
                if (String.IsNullOrEmpty(ordernumber) || String.IsNullOrEmpty(type)) return;
            }
            catch
            {
                throw new Exception("Break");
            }

            SearchCriteria search = new SearchCriteria();

            double? temp = (double?)(range.Cells[index, 1] as Excel.Range).Value2;
            DateTime? date = temp.HasValue ? DateTime.FromOADate(temp.Value) : DateTime.MinValue;
            string customerCode = (string)(range.Cells[index, 3] as Excel.Range).Value2;
            if (String.IsNullOrEmpty(customerCode))
                throw new BusinessLogicException("BLM_ERR_CUSTOMERCODE_REQUIRE");
            string countryCode = (string)(range.Cells[index, 5] as Excel.Range).Value2;
            if (String.IsNullOrEmpty(countryCode))
                throw new BusinessLogicException("BLM_ERR_COUNTRYCODE_REQUIRE");
            decimal? weight = Utility.DecimalNParse((object)(range.Cells[index, 7] as Excel.Range).Value2);

            if (!temp.HasValue)
                throw new BusinessLogicException("BLM_ERR_DATE_REQUIRE");
            if (!weight.HasValue)
                throw new BusinessLogicException("BLM_ERR_WEIGHT_REQUIRE");
            if (String.IsNullOrEmpty(type))
                throw new BusinessLogicException("BLM_ERR_TYPE_REQUIRE");

            int customerID = 0;
            DataRow[] rows = customers.Select("PartnerCode = '" + customerCode + "'");
            if (rows.Length > 0)
                customerID = Utility.IntParse(rows[0]["PartnerID"]);
            else
                throw new BusinessLogicException("BLM_ERR_CUSTOMERCODE_NOT_EXIST");

            int countryID = 0;
            rows = countries.Select("CountryCode = '" + countryCode + "'");
            if (rows.Length > 0)
                countryID = Utility.IntParse(rows[0]["CountryID"]);
            else
                throw new BusinessLogicException("BLM_ERR_COUNTRYCODE_NOT_EXIST");

            OrderENT order = new OrderENT();
            order.OrderDate = date;
            order.OrderNumber = ordernumber;
            order.SupplierID = supplierID;
            order.CustomerID = customerID;
            order.CarrierID = carrierID;
            order.CountryID = countryID;
            order.Type = type;
            order.Weight = weight;
            order.Rate = (decimal?)(range.Cells[index, 8] as Excel.Range).Value2;
            order.Cost = (decimal?)(range.Cells[index, 9] as Excel.Range).Value2;
            order.Fuel = (decimal?)(range.Cells[index, 11] as Excel.Range).Value2;
            order.VAT = (decimal?)(range.Cells[index, 12] as Excel.Range).Value2;

            int originalPriceListID, customerPriceListID;
            order.StandardPrice = _task.LoadOriginalPrice(supplierID, carrierID, countryID, type, weight.Value, date.Value, out originalPriceListID);
            order.ListPrice = _task.LoadCustomerPrice(customerID, carrierID, supplierID, countryID, type, weight.Value, date.Value, out customerPriceListID);

            order.OriginalPriceListID = originalPriceListID;
            order.CustomerPriceListID = customerPriceListID;
            order.CreatedBy = UserENT.USERID;
            order.UpdatedBy = UserENT.USERID;

            try
            {
                _task.Insert(order);
            }
            catch (BusinessLogicException)
            {
            }
        }

        public void ExportExcel(string fileName, int totalCount, DateTime from, DateTime to, Dictionary<string, DataTable> tables, Dictionary<string, string> text, string template)
        {
            Excel.Application xlApp = null;
            Excel.Workbooks xlWorkBooks = null;
            Excel.Workbook xlWorkBook = null;
            Excel.Sheets xlWorkSheets = null;
            Excel.Worksheet xlWorkSheet = null;
            Excel.Worksheet xlTemplate = null;

            try
            {
                _view.UpdateValueProgressBar(0);
                _view.ChangeProgressBarMaximum(totalCount);
                _view.ChangeProgressBarVisible(true);

                xlApp = new Excel.Application();
                xlWorkBooks = xlApp.Workbooks;
                xlWorkBook = xlWorkBooks.Open(template, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

                xlWorkSheets = xlWorkBook.Worksheets;
                xlTemplate = (Excel.Worksheet)xlWorkSheets.get_Item(1);

                int sheetIndex = 1;
                foreach (KeyValuePair<string, DataTable> item in tables)
                {
                    xlWorkSheet = (Excel.Worksheet)xlWorkSheets.get_Item(sheetIndex);
                    xlTemplate.Copy(Type.Missing, xlWorkSheet);
                    xlWorkSheet = (Excel.Worksheet)xlWorkSheets.get_Item(++sheetIndex);
                    xlWorkSheet.Name = String.IsNullOrEmpty(item.Key) ? "Tổng kết" : text[item.Key];
                    xlWorkSheet.Cells[1, 1] = "SỐ LIỆU " + from.ToShortPattern(Utility.Info) + " - " + to.ToShortPattern(Utility.Info);

                    int rowCount = item.Value.Rows.Count;
                    int rowIndex = 3;
                    for (int i = 0; i < rowCount; i++)
                    {
                        xlWorkSheet.Cells[rowIndex + i, 1] = item.Value.Rows[i]["OrderDate"];
                        xlWorkSheet.Cells[rowIndex + i, 2] = item.Value.Rows[i]["OrderNumber"];
                        xlWorkSheet.Cells[rowIndex + i, 3] = item.Value.Rows[i]["CustomerName"];
                        xlWorkSheet.Cells[rowIndex + i, 4] = item.Value.Rows[i]["CountryName"];
                        xlWorkSheet.Cells[rowIndex + i, 5] = item.Value.Rows[i]["Type"];
                        xlWorkSheet.Cells[rowIndex + i, 6] = item.Value.Rows[i]["Weight"];
                        xlWorkSheet.Cells[rowIndex + i, 7] = String.Empty;
                        xlWorkSheet.Cells[rowIndex + i, 8] = String.Empty;
                        xlWorkSheet.Cells[rowIndex + i, 9] = item.Value.Rows[i]["StandardPrice"];
                        xlWorkSheet.Cells[rowIndex + i, 10] = item.Value.Rows[i]["ListPrice"];
                        xlWorkSheet.Cells[rowIndex + i, 11] = item.Value.Rows[i]["VNDStandardPrice"];
                        xlWorkSheet.Cells[rowIndex + i, 12] = item.Value.Rows[i]["VNDListPrice"];
                        xlWorkSheet.Cells[rowIndex + i, 13] = item.Value.Rows[i]["Description"];

                        _view.PerformStepProgressBar(1);
                    }
                }

                //// save the application
                xlWorkBook.SaveAs(fileName, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                    Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

                _view.UpdateValueProgressBar(totalCount);
            }
            catch (Exception ex)
            {
                Log.LogEx(Message.BLM_ERR_GENERAL.ToString(), Log.LogType.Error, ex);
            }
            finally
            {
                xlApp.Quit();

                //// these are some cleanup calls
                System.Threading.Thread.Sleep(1000);

                Marshal.ReleaseComObject(xlApp);
                if (xlWorkSheet != null) Marshal.ReleaseComObject(xlWorkSheet);
                if (xlWorkSheets != null) Marshal.ReleaseComObject(xlWorkSheets);
                if (xlWorkBook != null) Marshal.ReleaseComObject(xlWorkBook);
                if (xlWorkBooks != null) Marshal.ReleaseComObject(xlWorkBooks);
                if (xlApp != null) Marshal.ReleaseComObject(xlApp);

                _view.ChangeProgressBarVisible(false);
            }
        }
    }
}